/*

Archivo: "globals.h"

Implementación del "handle" del conjunto para el "bridge".

Autor: Diego Luna

Primera versión: 5-6-2012

*/


#ifndef __SET_H_INCLUDED
#define __SET_H_INCLUDED

#include <cstdlib>
#include <iostream>
#include <string>
#include "globals.h"
#include "bases.h"

/* ========================= SetHandle - Begin ========================== */
// Clase abstracta base para la implementación de los contenedores usados por
// el conjunto. La clase es abastracta y solo define una interfaz.

template <typename T>
class SetHandle
{

public:

    // Tipos definidos en forma standard para un "container" compatible con la STL.
    typedef T valueTpe;
    typedef valueTpe& reference;
    typedef const valueTpe& const_reference;
    typedef Base_Iterator<T, DEFAULT_ITERATOR> iterator;
    //typedef const Base_Iterator<T, DEFAULT_ITERATOR> const_iterator;
    typedef int differenceTpe;
    typedef size_t sizeTpe;

    // ++++++++++++++++++++++++ Constructores\Destructores - Begin +++++++++++++++++++++++++++++

    // Constructor.
    SetHandle(SetImplementation<T>*);

    // Constructor copia.
    SetHandle(const SetHandle<T>&);

    // Destructor.
    virtual ~SetHandle();

    // ++++++++++++++++++++++++ Constructores\Destructores - End +++++++++++++++++++++++++++++++


    // ++++++++++++++++++++++++ Métodos públicos - Begin +++++++++++++++++++++++++++++++++++++++

    // Devuelve el iterador al primer elemento.
    virtual iterator begin() const;

    // Devuelve el iterador al siguiente al último elemento.
    virtual iterator end() const;

    // Devuelve el iterador al anterior al primer elemento.
    virtual iterator rend() const;

    // Devuelve el iterador al último elemento.
    virtual iterator rbegin() const;

    // Agrega un elemento al contenedor.
    virtual bool add(const T&);

    // Agrega un elemento al contenedor y devuelve un iterador al mismo,
    // o al elemento existente en caso de existir previamente.
    virtual iterator add_or_get(const T&);

    // Elimina un elemento del contenedor (si se encuentra).
    virtual bool remove(const T&);

    // Determina si un elemento se encuentra en el contenedor.
    virtual bool includes(const T&) const;

    // Vacía el contenedor.
    virtual void wipe();

    // Determina si el contenedor esta vacío.
    virtual bool is_empty() const;

    // Devuelve la cantidad de elementos en el contenedor.
    virtual size_t size() const;

    // Imprime los elementos contenidos.
    virtual void print(std::ostream&) const;

    // Devuelve un string que identifica a la clase del contenedor.
    virtual std::string implementor_class_ID() const;

    // Asigna un nuevo "implementor" al objeto "handle".
    void set_implementor(SetImplementation<T>*);

    // Devuelve el "implementor" asociado al objeto "handle".
    SetImplementation<T>* get_implementor();

    // ++++++++++++++++++++++++ Métodos públicos - End ++++++++++++++++++++++++++++++++++++++++++


    // ++++++++++++++++++++++++ Operadores - Begin ++++++++++++++++++++++++++++++++++++++++++++++

    // Operador de asignación.
    SetHandle<T>& operator=(const SetHandle<T>&);

    // Operador de comparación por igualdad.
    bool operator==(const SetHandle<T>&);

    // Operador de comparación por desigualdad.
    bool operator!=(const SetHandle<T>&);

    // Operador de salida.
    std::ostream& operator<<(std::ostream &);

    // ++++++++++++++++++++++++ Operadores - End ++++++++++++++++++++++++++++++++++++++++++++++++

protected:

    //************************
    // Atributos de SetHandle.

    // Puntero a la implementación.
    SetImplementation<T>* pimplementor_;
    //************************


    // ++++++++++++++++++++++++ Métodos protegidos - Begin +++++++++++++++++++++++++++++++++++++++

    // Verifica que el puntero al "implementor" esté asignado,
    // en caso de no estarlo termina el programa.
    // Se llama a este método antes de intentar llamar a un método
    // del "implementor".
    void verify_implementor() const;

    // ++++++++++++++++++++++++ Métodos protegidos - End +++++++++++++++++++++++++++++++++++++++++


private:

    // ++++++++++++++++++++++++ Métodos privados - Begin ++++++++++++++++++++++++++++++++++++++++


    // ++++++++++++++++++++++++ Métodos privados - End ++++++++++++++++++++++++++++++++++++++++++

};

/* ========================= SetHandle - End ============================ */


// ++++++++++++++++++++++++ Constructores\Destructores [SetHandle] - Begin +++++++++++++++++++++++++++++

// Constructor.
template <typename T>
SetHandle<T>::SetHandle(SetImplementation<T>* pimplementor): pimplementor_(pimplementor)
{
}

// Constructor copia.
template <typename T>
SetHandle<T>::SetHandle(const SetHandle<T>& set): pimplementor_(NULL)
{
    // Llamo al operador de asignación.
    *this = set;
}

// Destructor.
template <typename T>
SetHandle<T>::~SetHandle()
{
}

// ++++++++++++++++++++++++ Constructores\Destructores [SetHandle] - End +++++++++++++++++++++++++++++++


// ++++++++++++++++++++++++ Métodos públicos [SetHandle] - End ++++++++++++++++++++++++++++++++++++++++++++

// Devuelve el iterador al primer elemento.
template <typename T>
typename SetHandle<T>::iterator SetHandle<T>::begin() const
{
    verify_implementor();
    return pimplementor_->begin();
}

// Devuelve el iterador al siguiente al último elemento.
template <typename T>
typename SetHandle<T>::iterator SetHandle<T>::end() const
{
    verify_implementor();
    return pimplementor_->end();
}

// Devuelve el iterador al anterior al primer elemento.
template <typename T>
typename SetHandle<T>::iterator SetHandle<T>::rend() const
{
    verify_implementor();
    return pimplementor_->rend();
}

// Devuelve el iterador al último elemento.
template <typename T>
typename SetHandle<T>::iterator SetHandle<T>::rbegin() const
{
    verify_implementor();
    return pimplementor_->rbegin();
}

// Agrega un elemento al contenedor.
template <typename T>
bool SetHandle<T>::add(const T& key)
{
    verify_implementor();
    return pimplementor_->add(key, false);
}

// Agrega un elemento al contenedor y devuelve un iterador al mismo,
// o al elemento existente en caso de existir previamente.
template <typename T>
typename SetHandle<T>::iterator SetHandle<T>::add_or_get(const T& key)
{
    verify_implementor();
    return pimplementor_->add_or_get(key);
}

// Elimina un elemento del contenedor (si se encuentra).
template <typename T>
bool SetHandle<T>::remove(const T& key)
{
    verify_implementor();
    return pimplementor_->remove(key);
}

// Determina si un elemento se encuentra en el contenedor.
template <typename T>
bool SetHandle<T>::includes(const T& key) const
{
    verify_implementor();
    return pimplementor_->includes(key);
}

// Vacía el contenedor.
template <typename T>
void SetHandle<T>::wipe()
{
    verify_implementor();
    pimplementor_->wipe();
}

// Determina si el contenedor esta vacío.
template <typename T>
bool SetHandle<T>::is_empty() const
{
    verify_implementor();
    return pimplementor_->is_empty();
}

// Devuelve la cantidad de elementos en el contenedor.
template <typename T>
size_t SetHandle<T>::size() const
{
    verify_implementor();
    return pimplementor_->size();
}

// Imprime los elementos contenidos.
template <typename T>
void SetHandle<T>::print(std::ostream& oss) const
{
    verify_implementor();
    pimplementor_->print(oss);
}

// Devuelve un string que identifica a la clase del contenedor.
template <typename T>
std::string SetHandle<T>::implementor_class_ID() const
{
    verify_implementor();
    return pimplementor_->class_ID();
}

// Asigna un nuevo "implementor" al objeto.
template <typename T>
void SetHandle<T>::set_implementor(SetImplementation<T>* pimplementor)
{
    pimplementor_ = pimplementor;
}

// Devuelve el "implementor" asociado al objeto "handle".
template <typename T>
SetImplementation<T>* SetHandle<T>::get_implementor()
{
    return pimplementor_;
}

// ++++++++++++++++++++++++ Métodos públicos [SetHandle] - End ++++++++++++++++++++++++++++++++++++++++++++


// ++++++++++++++++++++++++ Operadores [SetHandle] - Begin ++++++++++++++++++++++++++++++++++++++++++++++++

// Operador de asignación.
template <typename T>
SetHandle<T>& SetHandle<T>::operator=(const SetHandle<T>& set)
{
    // Dado que no está especificado el comportamiento exacto en este caso,
    // lo decidido fué en caso de no tener "implementor" propio, usar el del
    // "handle" original y en caso de sis tenerlo se copia el contenido.
    if ((pimplementor_ == NULL) && (set.pimplementor_ != NULL))
        pimplementor_ = set.pimplementor_;
    else if ((pimplementor_ != NULL) && (set.pimplementor_ != NULL))
        *pimplementor_ = *(set.pimplementor_);
    else
        pimplementor_ = NULL;

    return *this;
}

// Operador de comparación por igualdad.
template <typename T>
bool SetHandle<T>::operator==(const SetHandle<T>& set)
{
    // Defino que dos conjuntos son iguales cuando ambos apuntan
    // al mismo "implementor" (incluso si ambos son NULL) o
    // cuándo ambos apuntan a distintos "implementor", pero que
    // contienen los mismos elementos.
    if (pimplementor_ == set.pimplementor_)
        return true;
    else if ((pimplementor_ == NULL) || (set.pimplementor_ == NULL) ||
             (pimplementor_->size() != set.pimplementor_->size()))
        return false;
    else
    {
        for (iterator it = begin(); it != end(); it++)
        {
            if (!set.includes(*it))
                return false;
        }

        return true;
    }
}

// Operador de comparación por desigualdad.
template <typename T>
bool SetHandle<T>::operator!=(const SetHandle<T>& set)
{
    return !(*this == set);
}

// Operador de salida.
template <typename T>
std::ostream& SetHandle<T>::operator<<(std::ostream &oss)
{
	print(oss);

	return oss;
}

// ++++++++++++++++++++++++ Operadores [SetHandle] - End ++++++++++++++++++++++++++++++++++++++++++++++++++


// ++++++++++++++++++++++++ Métodos protegidos [SetHandle] - Begin ++++++++++++++++++++++++++++++++++++++++

// Verifica que el puntero al "implementor" esté asignado,
// en caso de no estarlo termina el programa.
// Se llama a este método antes de intentar llamar a un método
// del "implementor".
template <typename T>
void SetHandle<T>::verify_implementor() const
{
    if (pimplementor_ == NULL)
    {
        FATAL_ERROR(BAD_IMPLEMENTOR);
    }
}

// ++++++++++++++++++++++++ Métodos protegidos [SetHandle] - End ++++++++++++++++++++++++++++++++++++++++++


#endif
